package cate.game.role.bag.hero;

import cate.common.table.d.GDObj;
import cate.common.table.item.hero.row.HeroBaseRow;
import cate.common.table.item.yoke.row.HeroLimitRow;
import cate.common.table.item.yoke.row.YokeGridRow;
import cate.common.table.item.yoke.row.YokeStarLimitRow;
import cate.common.util.GameResult;
import cate.game.attr.PowerAttrPart;
import cate.game.attr.YokePowerAttrPart;
import cate.game.play.support.PlayBuildContext;
import cate.game.role.Role;
import cate.game.role.RoleDependent;
import cate.game.role.bag.IBagContainer;
import cate.game.train.hero.msg.HeroLockResp;
import cate.game.train.yoke.msg.YokeOffResp;
import com.fasterxml.jackson.annotation.JsonIgnore;
import cp.solution.pattern.ICopiable;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.annotation.Transient;

import java.util.HashMap;
import java.util.Map;

@NoteClass(value = "英雄身上的羁绊英雄")
public class YokeOn extends RoleDependent implements ICopiable<YokeOn> {
    @JsonIgnore
    @Transient
    public transient Hero owner;

    @NoteField(value = "英雄身上的羁绊英雄们", detail = "Map<部位:Byte, 装备信息>")
    public Map<Byte, String> heroUidMap;

    public void initialize(Hero owner, Role role) {
        super.initialize(role);
        this.owner = owner;
        if (heroUidMap == null) {
            heroUidMap = new HashMap<>();
        }
    }

    @JsonIgnore
    public IBagContainer<Hero> getItemBag() {
        return role.getBag().getBag(GDObj.Type.HERO);
    }

    public Hero getPosItem(byte pos) {
        String heroUid = heroUidMap.get(pos);
        if (StringUtils.isNotBlank(heroUid)) {
            return role.getBag().hero.getItem(heroUid);
        }
        return null;
    }

    public GameResult<Void> preCheckOn(PlayBuildContext ctx, byte pos, Hero hero) {
        GameResult<Void> r = new GameResult<>();
        YokeGridRow gridRow = role.getGame().table.yoke.yokeGrid.get((int) pos);
        if (gridRow == null) {
            return r.fail("格子不存在");
        }
        if (hero.yokeOn.heroUidMap.size() > 0) {
            return r.fail("已穿戴羁绊的英雄不可作为羁绊英雄");
        }
        Hero m = owner;
        if (hero.lock.heroYoke) {
            return r.fail("不可重复装配");
        }
        if (hero.lock.heroContract) {
            return r.fail("星池中的英雄不可作为羁绊英雄");
        }
        HeroBaseRow mTpl = m.getTpl(ctx);
        if (mTpl == null) {
            return r.fail("英雄配置有误");
        }
        if (mTpl.star < gridRow.openStar) {
            return r.fail("格子未开启");
        }
        YokeStarLimitRow limitRow = role.getGame().table.yoke.starLimit.getRowByStar(mTpl.star);
        if (limitRow == null) {
            return r.fail("此英雄羁绊未开启");
        }
        HeroLimitRow heroLimit = role.getGame().table.yoke.heroLimit.getRowByProtoId(mTpl.protoId);
        if (heroLimit == null) {
            return r.fail("英雄羁绊未配置");
        }

        HeroBaseRow sTpl = hero.getTpl(ctx);
        if (sTpl == null) {
            return r.fail("羁绊英雄配置错误");
        }
        if (sTpl.star < limitRow.slaveMinStar || sTpl.star > limitRow.slaveMaxStar) {
            return r.fail("羁绊英雄星级不匹配");
        }
        HeroLimitRow.Limit l = heroLimit.getLimit(pos);
        if (l != null && !match(l, sTpl)) {
            return r.fail("羁绊英雄不可上此位置");
        }
        return r;
    }

    public GameResult<Byte> on(PlayBuildContext ctx, byte pos, Hero slave) {
        GameResult<Byte> r = new GameResult<>();
        if (slave == null || slave.num <= 0) {
            return r.fail("羁绊英雄不存在");
        }
        GameResult<Void> checkRes = preCheckOn(ctx, pos, slave);
        if (!checkRes.ok()) {
            return r.fail(checkRes);
        }
        Hero pre = getPosItem(pos);
        if (pre != null) {
            off(pos);
            role.sendNow(new YokeOffResp(this.owner.uid, pos));
        }
        doRealOn(pos, slave);
        return r;
    }


    public GameResult<Byte> off(byte pos) {
        GameResult<Byte> r = new GameResult<>();
        Hero slave = getPosItem(pos);
        if (slave == null) {
            return r.fail("英雄不存在");
        }
        doRealOff(pos, slave);
        r.data = pos;
        return r;
    }

    public void doRealOn(byte pos, Hero hero) {
        hero.lock.heroYoke = true;
        heroUidMap.put(pos, hero.uid);
        role.sendNow(new HeroLockResp(hero.lock));
    }

    public void doRealOff(byte pos, Hero hero) {
        hero.lock.heroYoke = false;
        this.heroUidMap.remove(pos);
        role.sendNow(new HeroLockResp(hero.lock));
    }

    public PowerAttrPart getPowerAttrPart(PlayBuildContext ctx) {
        return new YokePowerAttrPart(ctx, this);
    }

    @Override
    public YokeOn copy() {
        YokeOn cp = new YokeOn();
        cp.heroUidMap = SerializationUtils.clone((HashMap<Byte, String>) this.heroUidMap);
        cp.initialize(this.owner, this.role);
        return cp;
    }

    private boolean match(HeroLimitRow.Limit limit, HeroBaseRow tpl) {
        switch (limit.type) {
            case 1:
                return tpl.camp == limit.limit;
            case 2:
                return tpl.protoId == limit.limit;
            default:
                return false;
        }
    }

    public void recheck() {
        for (String heroUid : heroUidMap.values()) {
            Hero hero = role.getBag().hero.getItem(heroUid);
            if (hero != null) {
                hero.lock.heroYoke = false;
                role.sendNow(new HeroLockResp(hero.lock));
            }
        }
        heroUidMap.clear();
    }

    public GameResult<Byte> offAll() {
        GameResult<Byte> r = new GameResult<>();
        if (heroUidMap == null || heroUidMap.isEmpty()) {
            return r.fail("该英雄没有装备任何羁绊英雄");
        }
        new HashMap<>(heroUidMap).keySet().forEach(this::off);
        return r;
    }
}
